package com.acron.xrpc.consumer;

import com.acron.xrpc.protool.InvokeProtocol;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by acron on 2022/2/19.
 */
public class ServiceProxy<T> {
    public static <T> T create(Class<T> clazz) {
        MethodProxy invocationHandler = new MethodProxy(clazz);
        Class<?>[] interfaces = clazz.isInterface() ? new Class[]{clazz} : clazz.getInterfaces();
        T clzObj = (T) Proxy.newProxyInstance(clazz.getClassLoader(), interfaces, invocationHandler);
        return clzObj;
    }

    private static class MethodProxy implements InvocationHandler {

        private Class<?> clazz;

        public MethodProxy(Class<?> clazz) {
            this.clazz = clazz;
        }


        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (Object.class.equals(method.getDeclaringClass())) {
                // 是实现类，调用返回
                return method.invoke(this, args);
            } else {
                // 是接口，实例化再调用返回
                return rpcInvoke(proxy, method, args);
            }
        }

        private Object rpcInvoke(Object proxy, Method method, Object[] args) {
            // 序列化 + 封装传输协议
            InvokeProtocol invokeProtocol = new InvokeProtocol();
            invokeProtocol.setClassName(this.clazz.getName());
            invokeProtocol.setMethodName(method.getName());
            invokeProtocol.setParams(method.getParameterTypes());
            invokeProtocol.setValues(args);
            // 网络通讯调用服务端
            final RpcProxyHandler consumerHandler = new RpcProxyHandler();
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                Bootstrap bootstrap = new Bootstrap();
                ChannelFuture channelFuture = bootstrap.group(group)
                        .channel(NioSocketChannel.class)
                        .option(ChannelOption.TCP_NODELAY, true)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                // 定制协议解码器
                                ch.pipeline().addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,
                                        0, 4, 0, 4))
                                        // 定制协议编码器
                                        .addLast("frameEncoder", new LengthFieldPrepender(4))
                                        // 对象参数编码器
                                        .addLast("objectEncoder", new ObjectEncoder())
                                        // 对象参数解码器
                                        .addLast("objectDecoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)))
                                        // 业务逻辑
                                        .addLast("handler", consumerHandler);

//                                ChannelPipeline pipeline = ch.pipeline();
//                                pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
//                                //自定义协议编码器
//                                pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
//                                //对象参数类型编码器
//                                pipeline.addLast("encoder", new ObjectEncoder());
//                                //对象参数类型解码器
//                                pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
//                                pipeline.addLast("handler",consumerHandler);

                            }
                        }).connect("127.0.0.1", 8080).sync();
                channelFuture.channel().writeAndFlush(invokeProtocol);
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                group.shutdownGracefully();
            }
            return consumerHandler.getResponse();
        }
    }
}
